/**
 * simple utilities for common usage
 */
var uxperf = uxperf || {};
module.exports = uxperf.utils = {};
	
/**
 * iterate over each property in object
 *
 * @param {!Object} obj object to iterate
 * @param {!Function} iterator function to execute for each property
 *                    it will have 3 arguments provided:
 *                    - property name
 *                    - property value
 *                    - result of previous execution of function
 * @param {Object=} opt_context optional context of iterator execution (value available in this)
 * @param {*=} opt_init optional initial value passed as third
 *            argument for first iterator execution
 * @return {*}
 */
uxperf.utils.each = function(obj, iterator, opt_context, opt_init) {
  var res = opt_init;
	for (var i in obj) res = iterator.call(opt_context, i, obj[i], res);
	return res;
};

/** @constant default recursion limit */
uxperf.utils.DEFAULTS_MAX_RLEVEL = 5;

/**
 * set default values in object
 * supports embeded sub objects to be set to default
 *
 * @param {!Object} result object to set
 * @param {Object} def object with default data
 * @param {number=} opt_maxrlevel maximum recursion level
 *                  set to -1 for no limit (5 by default)
 * @param {number=} opt_rlevel do not set this parameter
 *                  (parameter used internaly for
 *                  recursion level checking)
 * @return {!Object} reference to result object
 */
uxperf.utils.defaults = function (result, def, opt_maxrlevel, opt_rlevel) {
	if (!def) return result;
	opt_rlevel = opt_rlevel || 0;
	opt_maxrlevel = opt_maxrlevel || uxperf.utils.DEFAULTS_MAX_RLEVEL;
	//NDEBUG || console.log('current rlevel = ', opt_rlevel);
	if ((opt_maxrlevel >= 0) && (opt_rlevel >= opt_maxrlevel)) return result;
	for(var k in def) {
		//NDEBUG || console.log('k=%s, type of def[k]=%s, res[k]=%j', k, typeof def[k], result[k]);
		if (result[k]===undefined) {
			//NDEBUG || console.log('res[k] is undefined so res[k]=def[k]=%j',def[k]);
			result[k] = def[k];
		} else if ( (result[k] && (typeof result[k] === 'object') || (typeof result[k] === 'array'))
								&& ((typeof def[k] === 'object') || (typeof def[k] === 'array')) ) {
			//NDEBUG || console.log('res[k] is not null and is object or array and def[k] is object or array so recurent call is executed');
			result[k] = uxperf.utils.defaults(result[k], def[k], opt_maxrlevel, opt_rlevel + 1);
		}
	}
	return result;
};

/**
 * overrides values in object
 * supports embeded sub objects to be set
 *
 * @param {!Object} result object to set
 * @param {Object} data object with overriding data
 * @param {number=} opt_maxrlevel maximum recursion level
 *                  set to -1 for no limit (5 by default)
 * @param {number=} opt_rlevel do not set this parameter
 *                  (parameter used internaly for
 *                  recursion level checking)
 * @return {!Object} reference to result object
 */
uxperf.utils.overrides = function (result, data, opt_maxrlevel, opt_rlevel) {
	if (!data) return result;
	opt_rlevel = opt_rlevel || 0;
	opt_maxrlevel = opt_maxrlevel || uxperf.utils.DEFAULTS_MAX_RLEVEL;
	//NDEBUG || console.log('current rlevel = ', opt_rlevel);
	if ((opt_maxrlevel >= 0) && (opt_rlevel >= opt_maxrlevel)) return result;
	for(var k in data) {
		//NDEBUG || console.log('k=%s, type of data[k]=%s, res[k]=%j', k, typeof data[k], result[k]);
		if ( (result[k] && (typeof result[k] === 'object') || (typeof result[k] === 'array'))
								&& ((typeof data[k] === 'object') || (typeof data[k] === 'array')) ) {
			//NDEBUG || console.log('res[k] is not null and is object or array and def[k] is object or array so recurent call is executed');
			result[k] = uxperf.utils.overrides(result[k], data[k], opt_maxrlevel, opt_rlevel + 1);
		} else {
			//NDEBUG || console.log('res[k] is not array or object so set res[k]=data[k]=%j',data[k]);
			result[k] = data[k];			
		}
	}
	return result;
};
